function foo() {
  var name = 'foo'
  var age = 10
  
  function bar() {
    //访问到了外层作用域的自由变量name
    //对于V8引擎来说，如果此处没有引用到的外层变量将被销毁
    console.log('bar', name)
    debugger//暂停调试
    age = age + 10
    console.log(age)
  }
  
  return bar
}

var fn = foo()
fn()
fn()

var fn1 = foo()
fn1()
//fn1和fn是两个不同的变量，指向不同的内存空间，即如果fn=null，fn之前指向的一些空间将被释放
// 但是并不影响fn1指向空间，不会销毁
// foo执行一次，将产生新的AO(foo),AO(bar),foo对象，bar对象

//闭包
/**
 * 维基百科
 *  闭包(英语:Closure)，又称词法闭包(Lexical Closure)或函数闭包(function closures);
 *  是在支持 头等函数 的编程语言中，实现词法绑定的一种技术
 *  闭包在实现上是一个结构体，它存储了一个函数和一个关联的环境(相当于一个符号查找表)
 *  闭包跟函数最大的区别在于，当捕捉闭包的时候，它的 自由变量 会在捕捉时被确定，这样即使脱离了捕捉时的上下文，它也能照常运行
 */

/**
 * MDN
 *  一个函数和对其周围状态(lexical environment，词法环境)的引用捆绑在一起(或者说函数被引用包围)，这样的组合就是闭包(closure)
 *  也就是说，闭包让你可以在一个内层函数中访问到其外层函数的作用域
 *  在 JavaScript 中，每当创建一个函数，闭包就会在函数创建的同时被创建出来
 */

/**
 * coderwhy
 *  一个普通的函数function，如果它可以访问外层作用域的自由变量，那么这个函数就是一个闭包
 *  从广义的角度来说:JavaScript中的函数都是闭包
 *  从狭义的角度来说:JavaScript中一个函数，如果访问了外层作用域的变量，那么它是一个闭包
 */

//闭包的内存泄漏
/**
 * 拿该例子来说，fn是根对象的一个变量，内部存储了bar的引用，而bar的内部又引用了其父作用域中的变量name、age，因此foo的AO对象，bar
 * 的AO对象、bar对象都不会销毁，即使以后都不使用fn也是如此，就造成了该销毁的对象没有销毁的现象，也就是内存泄漏
 *
 * 解决办法： 执行完fn后，重新对fn进行赋值:
 * fn = null
 */


